/*
 * Copyright 2011 Angel Sanadinov
 *
 * This file is part of VBox WMI.
 *
 * VBox WMI is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * VBox WMI is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with VBox WMI.  If not, see <http://www.gnu.org/licenses/>.
 */

package Services;

import Beans.InternalNetworkBean;
import Beans.LogBean;
import Beans.PermissionsBean;
import Beans.Requests.AuthorizationRequest;
import Beans.Requests.DataRetrieval.DataRetrievalRequest;
import Beans.Requests.DataRetrieval.LogsDataRetrievalRequest;
import Beans.Requests.DataRetrieval.MachinesDataRetrievalRequest;
import Beans.Requests.DataRetrieval.MediaDataRetrievalRequest;
import Beans.Requests.DataRetrieval.MiscDataRetrievalRequest;
import Beans.Requests.DataRetrieval.NetworksDataRetrievalRequest;
import Beans.Requests.DataRetrieval.ServersDataRetrievalRequest;
import Beans.Requests.DataRetrieval.SnapshotsDataRetrievalRequest;
import Beans.Requests.DataRetrieval.SystemDataRetrievalRequest;
import Beans.Requests.DataRetrieval.UsersDataRetrievalRequest;
import Beans.Requests.DataRetrieval.VBoxResourceRequest;
import Beans.Requests.MachineManagement.Components.AudioSettings;
import Beans.Requests.MachineManagement.Components.BIOSSettings;
import Beans.Requests.MachineManagement.Components.BootSettings;
import Beans.Requests.MachineManagement.Components.CPUSettings;
import Beans.Requests.MachineManagement.Components.IOSettings;
import Beans.Requests.MachineManagement.Components.MemorySettings;
import Beans.Requests.MachineManagement.Components.NATEngineForwardingRule;
import Beans.Requests.MachineManagement.Components.NATEngineSettings;
import Beans.Requests.MachineManagement.Components.NetworkAdapterSettings;
import Beans.Requests.MachineManagement.Components.SharedFolderSettings;
import Beans.Requests.MachineManagement.Components.VRDPSettings;
import Beans.Requests.MachineManagement.Components.VideoSettings;
import Beans.Requests.NetworkManagement.Components.DHCPServerConfiguration;
import Beans.Requests.NetworkManagement.Components.HostNetworkConfiguration;
import Beans.Requests.NetworkManagement.Components.InternalNetworkConfiguration;
import Beans.Requests.RequestBean;
import Beans.Requests.SimpleAuthorizationRequest;
import Beans.Responses.DataRetrievalComponents.LogDataComponent;
import Beans.Responses.DataRetrievalComponents.MachineDataComponent;
import Beans.Responses.DataRetrievalComponents.MachineSnapshotDataComponent;
import Beans.Responses.DataRetrievalComponents.MachineStorageData;
import Beans.Responses.DataRetrievalComponents.MediumDataComponent;
import Beans.Responses.DataRetrievalComponents.MiscDataComponent;
import Beans.Responses.DataRetrievalComponents.NetworkDataComponent;
import Beans.Responses.DataRetrievalComponents.ServerDataComponent;
import Beans.Responses.DataRetrievalComponents.SystemDataComponent;
import Beans.Responses.DataRetrievalComponents.SystemHostData;
import Beans.Responses.DataRetrievalComponents.SystemVirtualBoxData;
import Beans.Responses.DataRetrievalComponents.UserDataComponent;
import Beans.Responses.DataRetrievalResponse;
import Beans.ServerBean;
import Beans.UserBean;
import Beans.VirtualResourceBean;
import Managers.DatabaseManager;
import Managers.LogsManager;
import Managers.PermissionsManager;
import Managers.SessionsManager;
import Managers.Utilities.RequestResponseWrapper;
import Managers.Utilities.ResponseMessagesContainer;
import Managers.VBoxConnectionsManager;
import Utilities.Constants;
import Utilities.ApplicationException;
import Utilities.ExceptionMessages;
import Utilities.Constants.ResourceIdType;
import Utilities.Constants.ResourceRequestType;
import Utilities.Constants.VirtualResourceType;
import Utilities.Functions;
import Utilities.ParameterNames;
import Utilities.PermissionsConstants;
import com.sun.xml.ws.commons.virtualbox_3_2.IBIOSSettings;
import com.sun.xml.ws.commons.virtualbox_3_2.IDHCPServer;
import com.sun.xml.ws.commons.virtualbox_3_2.IGuestOSType;
import com.sun.xml.ws.commons.virtualbox_3_2.IHostNetworkInterface;
import com.sun.xml.ws.commons.virtualbox_3_2.IMachine;
import com.sun.xml.ws.commons.virtualbox_3_2.IMedium;
import com.sun.xml.ws.commons.virtualbox_3_2.IMediumAttachment;
import com.sun.xml.ws.commons.virtualbox_3_2.IMediumFormat;
import com.sun.xml.ws.commons.virtualbox_3_2.INATEngine;
import com.sun.xml.ws.commons.virtualbox_3_2.INetworkAdapter;
import com.sun.xml.ws.commons.virtualbox_3_2.ISharedFolder;
import com.sun.xml.ws.commons.virtualbox_3_2.IStorageController;
import com.sun.xml.ws.commons.virtualbox_3_2.IVRDPServer;
import com.sun.xml.ws.commons.virtualbox_3_2.IVirtualBox;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.ws.Holder;
import javax.xml.ws.WebServiceException;
import org.virtualbox_3_2.DeviceType;
import org.virtualbox_3_2.NATProtocol;
import org.virtualbox_3_2.NetworkAttachmentType;

/**
 * This servlet represents the application's Data Retrieval Service. <br><br>
 *
 * This service takes care of request for data retrieval.
 *
 * @author Angel Sanadinov
 */
public class DataService extends HttpServlet
{
    private DatabaseManager databaseManager;             //database manager
    private LogsManager logsManager;                     //logs manager
    private PermissionsManager permissionsManager;       //permissions manager
    private VBoxConnectionsManager connectionsManager;   //virtualbox connections manager
    private SessionsManager sessionsManager;             //sessions manager

    /**
     * Initializes the service and retrieves all necessary managers.
     *
     * @throws ServletException if an exception occurs that interrupts the servlet's
     *                          normal operation
     *
     * @see HttpServlet#init()
     */
    @Override
    public void init() throws ServletException
    {
        ServletContext context = getServletContext();
        databaseManager = (DatabaseManager)context.getAttribute(Constants.CONTEXT_DATABASE_MANAGER);
        logsManager = (LogsManager)context.getAttribute(Constants.CONTEXT_LOGS_MANAGER);
        permissionsManager = (PermissionsManager)context.getAttribute(Constants.CONTEXT_PERMISSIONS_MANAGER);
        connectionsManager = (VBoxConnectionsManager)context.getAttribute(Constants.CONTEXT_VBOX_CONNECTIONS_MANAGER);
        sessionsManager = (SessionsManager)getServletContext().getAttribute(Constants.CONTEXT_SESSIONS_MANAGER);
    }

    /**
     * Shuts down the service and cleans up any object references.
     *
     * @see HttpServlet#destroy()
     */
    @Override
    public void destroy()
    {
        databaseManager = null;
        logsManager = null;
        permissionsManager = null;
        connectionsManager = null;
        sessionsManager = null;
    }

    /**
     * Processes a <code>GET</code> request from a client.
     *
     * @param request an HttpServletRequest object that contains the request the
     *                client has made of the servlet
     * @param response an HttpServletResponse object that contains the response
     *                 the servlet sends to the client
     * @throws ServletException if the request for the GET could not be handled
     * @throws IOException if an input or output error is detected when the servlet
     *         handles the GET request
     *
     * @see HttpServlet#doGet(HttpServletRequest, HttpServletResponse)
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        processRequest(request, response);
    }

    /**
     * Processes a <code>POST</code> request from a client.
     *
     * @param request an HttpServletRequest object that contains the request the
     *                client has made of the servlet
     * @param response an HttpServletResponse object that contains the response
     *                 the servlet sends to the client
     * @throws ServletException if the request for the POST could not be handled
     * @throws IOException if an input or output error is detected when the servlet
     *         handles the POST request
     *
     * @see HttpServlet#doPost(HttpServletRequest, HttpServletResponse)
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        processRequest(request, response);
    }

    /**
     * Processes all <code>GET</code> and <code>POST</code> requests and carries out
     * operations based on requested actions.
     *
     * @param request an HttpServletRequest object that contains the request the
     *                client has made of the servlet
     * @param response an HttpServletResponse object that contains the response
     *                 the servlet sends to the client
     * @throws ServletException if the request could not be handled
     * @throws IOException if an input or output error is detected when the service
     *         handles the request
     */
    private void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        //retrieves the data retrieval request
        DataRetrievalRequest dataRequest =
                (DataRetrievalRequest)request.getAttribute(ParameterNames.REQUEST_DATA_RETRIEVAL);

        //checks that the request is available and is valid
        if(dataRequest != null && dataRequest.isValid())
        {
            logsManager.logSystemEvent(System.currentTimeMillis(), Constants.LOG_SEVERITY_DEBUG,
                                       "Request: " + dataRequest.toString());

            //attempts to authorize the request
            boolean isActionAuthorized = false;
            if(dataRequest.getResourceIdType() == ResourceIdType.NUMERIC_ID)
                isActionAuthorized = true; //authorization will be done in the methods
            else if(dataRequest.getResourceIdType() == ResourceIdType.UUID)
            {
                if(dataRequest.getResourceRequestType() == ResourceRequestType.SINGLE_RESOURCE)
                {
                    AuthorizationRequest authRequest =
                            new AuthorizationRequest(dataRequest.getRequestorId(),
                                                     dataRequest.getServerId(),
                                                     dataRequest.getRequestedAction(),
                                                     ((VBoxResourceRequest)dataRequest).getResourceType(),
                                                     ((VBoxResourceRequest)dataRequest).getResourceId());
                    
                    isActionAuthorized = permissionsManager.isActionAuthorized(authRequest);
                }
                else //multiple resources
                {
                    SimpleAuthorizationRequest authRequest =
                            new SimpleAuthorizationRequest(dataRequest.getRequestorId(),
                                                           dataRequest.getServerId(),
                                                           dataRequest.getRequestedAction(),
                                                           ((VBoxResourceRequest)dataRequest).getResourceType());

                    isActionAuthorized = permissionsManager.isActionAuthorized(authRequest);
                }
            }
            else
                ;

            //<editor-fold defaultstate="collapsed" desc="Action Selection">
            //checks if the request is authorized...
            if(isActionAuthorized)
            {
                //carries out the appropriate action based on the request data
                switch(dataRequest.getRequestedAction())
                {
                    //user(s) data is to be retrieved
                    case PermissionsConstants.ACTION_RETRIEVE_USERS:
                    {
                        processResponse(request, retrieveUsersData((UsersDataRetrievalRequest) dataRequest));
                    } break;

                    //server(s) data is to be retrieved
                    case PermissionsConstants.ACTION_RETRIEVE_SERVERS:
                    {
                        processResponse(request, retrieveServersData((ServersDataRetrievalRequest)dataRequest));
                    } break;

                    //logs data is to be retrieved
                    case PermissionsConstants.ACTION_RETRIEVE_LOGS:
                    {
                        processResponse(request, retrieveLogsData((LogsDataRetrievalRequest)dataRequest));
                    } break;

                    //system data is to be retrieved
                    case PermissionsConstants.ACTION_RETRIEVE_SYSTEM:
                    {
                        processResponse(request, retrieveSystemData((SystemDataRetrievalRequest)dataRequest));
                    } break;

                    //machine(s) data is to be retrieved
                    case PermissionsConstants.ACTION_RETRIEVE_MACHINES:
                    {
                        processResponse(request, retrieveMachinesData((MachinesDataRetrievalRequest)dataRequest));
                    } break;

                    //snapshots data is to be retrieved
                    case PermissionsConstants.ACTION_RETRIEVE_SNAPSHOTS:
                    {
                        processResponse(request, retrieveSnapshotsData((SnapshotsDataRetrievalRequest)dataRequest));
                    } break;

                    //medium/media data is to be retrieved
                    case PermissionsConstants.ACTION_RETRIEVE_MEDIA:
                    {
                        processResponse(request, retrieveMediaData((MediaDataRetrievalRequest)dataRequest));
                    } break;

                    //network(s) data is to be retrieved
                    case PermissionsConstants.ACTION_RETRIEVE_NETWORKS:
                    {
                        processResponse(request, retrieveNetworksData((NetworksDataRetrievalRequest)dataRequest));
                    } break;

                    case PermissionsConstants.ACTION_RETRIEVE_MISC:
                    {
                        processResponse(request, retrieveMiscellaneousData((MiscDataRetrievalRequest)dataRequest));
                    } break;

                    default:
                    {
                        processResponse(request, new DataRetrievalResponse(
                                new ApplicationException(ExceptionMessages.APP_E_INVALID_REQUESTED_ACTION)));
                    } break;
                }
            }
            else
                processResponse(request, new DataRetrievalResponse(new ApplicationException(ExceptionMessages.APP_E_OPERATION_NOT_ALLOWED)));
            //</editor-fold>
        }
        else
            processResponse(request, new DataRetrievalResponse(new ApplicationException(ExceptionMessages.APP_E_INVALID_REQUEST)));
    }

    /**
     * Processes all responses going out of the service.
     *
     * @param request an HttpServletRequest object that contains the request the
     *                client has made of the servlet
     * @param response an HttpServletResponse object that contains the response
     *                 the servlet sends to the client
     * @param dataResponse data retrieval response object
     * 
     * @throws ServletException if the processing of the response could not be handled
     * @throws IOException if an input or output error is detected when the response
     *                     is handled
     */
    private void processResponse(HttpServletRequest request, DataRetrievalResponse dataResponse)
            throws ServletException, IOException
    {
        //retrieves the request object from the session
        RequestBean requestData = (RequestBean)request.getAttribute(ParameterNames.REQUEST_DATA_RETRIEVAL);
        request.removeAttribute(ParameterNames.REQUEST_DATA_RETRIEVAL);
        request.setAttribute(ParameterNames.RESPONSE_DATA_RETRIEVAL, dataResponse);

        //checks if the requested action failed
        if(!dataResponse.getRequestResult())
        {
            //the request failed; retrieves the message container and stores the request/response pair
            ResponseMessagesContainer messagesContainer = (ResponseMessagesContainer)
                    request.getSession(false).getAttribute(ParameterNames.SESSION_REQUEST_MESSAGES_OBJECT);

            messagesContainer.put(new RequestResponseWrapper(requestData, dataResponse));

            logsManager.logSystemEvent(System.currentTimeMillis(), Constants.LOG_SEVERITY_DEBUG,
                                       "Request execution failed: " + dataResponse.getException().toString());
        }
        else
            ;
    }

    /**
     * Retrieves user(s) data.
     *
     * @param request user(s) data retrieval request
     * @return a response to the data retrieval request
     */
    private DataRetrievalResponse<UserDataComponent> retrieveUsersData(UsersDataRetrievalRequest request)
    {
        DataRetrievalResponse<UserDataComponent> result = null;

        //attempts to retrieve the requestor data from the sessions manager
        UserBean requestorData = sessionsManager.getUserData(request.getRequestorId());
        boolean isOperationAllowed = false;
        int userId = Utilities.Constants.INVALID_USER_ID;

        //determines whether the operation is allowed
        if(requestorData != null)
        {
            //checks if the requestor is a user manager
            if(requestorData.getAccountLevel() >= Constants.DB_USER_ACCOUNT_LEVEL_MANAGER)
            {
                isOperationAllowed = true;
                userId = request.getResourceId();
            }
            //checks if the requestor is asking for his/her own data
            else if(request.getResourceRequestType() == ResourceRequestType.SINGLE_RESOURCE
                    && request.getRequestorId() == request.getResourceId())
            {
                isOperationAllowed = true;
                userId = request.getRequestorId();
            }
            else
                ;
        }
        else
            ;

        //carries out the operation, if it is allowed
        if(isOperationAllowed)
        {
            //determines the type of resource to retrieve and return
            switch(request.getResourceRequestType())
            {
                //full data for a single user is to be returned
                case SINGLE_RESOURCE:
                {
                    //retrieves the user data
                    UserBean userData = databaseManager.getUser(userId);

                    if(userData != null && userData.isValid())
                    {
                        //retrieves the user permissions
                        ArrayList<PermissionsBean> permissions = databaseManager.getAllPermissionsForUser(userId);

                        //builds the data component and the result
                        UserDataComponent data = new UserDataComponent(userData, 
                                                                       sessionsManager.getUserData(userId) != null,
                                                                       permissions);
                        result = new DataRetrievalResponse<UserDataComponent>(data);
                    }
                    else
                    {
                        result = new DataRetrievalResponse<UserDataComponent>(
                                new ApplicationException(ExceptionMessages.APP_E_USER_RETRIEVAL_FAILED, "(" + userId + ")"));
                    }
                } break;

                //partial data for multiple users is to be returned
                case MULTIPLE_RESOURCES:
                {
                    ArrayList<UserDataComponent> data = new ArrayList<UserDataComponent>();
                    ArrayList<UserBean> usersData = databaseManager.getUsers();

                    //builds the response
                    for(UserBean userBean : usersData)
                        data.add(new UserDataComponent(userBean));

                    result = new DataRetrievalResponse<UserDataComponent>(data);
                } break;

                default: 
                {
                    result = new DataRetrievalResponse<UserDataComponent>(
                            new ApplicationException(ExceptionMessages.APP_E_RESOURCES_RETRIEVAL_FAILED));
                } break;
            }
        }
        else
            result = new DataRetrievalResponse<UserDataComponent>(new ApplicationException(ExceptionMessages.APP_E_OPERATION_NOT_ALLOWED));

        return result;
    }

    /**
     * Retrieves server(s) data.
     *
     * @param request server(s) data retrieval request
     * @return a response to the data retrieval request
     */
    private DataRetrievalResponse<ServerDataComponent> retrieveServersData(ServersDataRetrievalRequest request)
    {
        DataRetrievalResponse<ServerDataComponent> result = null;

        //attempts to retrieve the requestor data from the sessions manager
        UserBean requestorData = sessionsManager.getUserData(request.getRequestorId());

        //checks if the requestor data object was retrieved
        if(requestorData == null)
            return new DataRetrievalResponse<ServerDataComponent>(new ApplicationException(ExceptionMessages.APP_E_REQUESTOR_AUTHENTICATION_FAILED));
        else
            ;

        //full data for a single server is requested
        if(request.getResourceRequestType() == ResourceRequestType.SINGLE_RESOURCE)
        {
            boolean isOperationAllowed = false;

            //determines whether the operation is allowed
            if(requestorData.getAccountLevel() >= Constants.DB_USER_ACCOUNT_LEVEL_OWNER)
                isOperationAllowed = true;
            else
            {
                //checks if the user has any permissions on the requested server
                PermissionsBean serverPermissions =
                        databaseManager.getPermissions(request.getRequestorId(), request.getResourceId());
                if(serverPermissions != null)
                    isOperationAllowed = true;
                else
                    ;
            }

            //builds the response, if allowed and based on the user's WMI owner status
            if(isOperationAllowed)
            {
                ServerBean serverData = databaseManager.getServer(request.getResourceId());

                if(serverData != null && serverData.isValid())
                {
                    result = new DataRetrievalResponse<ServerDataComponent>(new ServerDataComponent(serverData, 
                            !(requestorData.getAccountLevel() >= Constants.DB_USER_ACCOUNT_LEVEL_OWNER)));
                }
                else
                {
                    result = new DataRetrievalResponse<ServerDataComponent>(
                            new ApplicationException(ExceptionMessages.APP_E_SERVER_RETRIEVAL_FAILED,
                                                     "(" + request.getResourceId() + ")"));
                }
            }
            else
            {
                result = new DataRetrievalResponse<ServerDataComponent>(
                        new ApplicationException(ExceptionMessages.APP_E_OPERATION_NOT_ALLOWED));
            }

        }
        else //partial data for multiple servers is requested
        {
            ArrayList<ServerDataComponent> data = new ArrayList<ServerDataComponent>();

            //checks if the user is WMI owner
            if(requestorData.getAccountLevel() >= Constants.DB_USER_ACCOUNT_LEVEL_OWNER)
            {
                //builds the response object
                ArrayList<ServerBean> serversData = databaseManager.getServers();
                for(ServerBean serverBean : serversData)
                    data.add(new ServerDataComponent(serverBean, false));
            }
            else
            {
                //retrieves the requestor's permission
                ArrayList<PermissionsBean> requestorPermissions 
                        = databaseManager.getAllPermissionsForUser(request.getRequestorId());

                if(requestorPermissions != null)
                {
                    //server data is retrieved only for servers that the requestor has access to
                    for(PermissionsBean serverPermissions : requestorPermissions)
                    {
                        ServerBean serverData = databaseManager.getServer(serverPermissions.getServerId());

                        if(serverData != null)
                            data.add(new ServerDataComponent(serverData, true));
                        else
                            ;
                    }
                }
                else
                    ;
            }

            result = new DataRetrievalResponse<ServerDataComponent>(data);
        }

        return result;
    }

    /**
     * Retrieves logs data.
     *
     * @param request logs data retrieval request
     * @return a response to the data retrieval request
     */
    private DataRetrievalResponse<LogDataComponent> retrieveLogsData(LogsDataRetrievalRequest request)
    {
        DataRetrievalResponse<LogDataComponent> result = null;

        //attempts to retrieve the requestor data from the sessions manager
        UserBean requestorData = sessionsManager.getUserData(request.getRequestorId());

        ArrayList<LogBean> logs = null;
        //retrieves the logs based on the limit set in the request
        switch(request.getLimit())
        {
            //no limit to logs retrieval (ie: get all available logs)
            case NO_LIMIT:
            {
                if(requestorData.getAccountLevel() >= Constants.DB_USER_ACCOUNT_LEVEL_OWNER)
                    logs = databaseManager.getLogs();
                else //non-owners can view only their own logs
                    logs = databaseManager.getLogsByInitiatorId(request.getRequestorId());
            } break;

            //limits logs by initiator id
            case INITIATOR_ID:
            {
                if(requestorData.getAccountLevel() >= Constants.DB_USER_ACCOUNT_LEVEL_OWNER)
                    logs = databaseManager.getLogsByInitiatorId(request.getLimitingResourceId());
                else if(request.getRequestorId() == request.getLimitingResourceId())
                    logs = databaseManager.getLogsByInitiatorId(request.getRequestorId());
                else //non-owners can't view any other user's logs
                    ;
            } break;

            //limits logs by server id
            case SERVER_ID:
            {
                //only WMI owners and server managers can retrieve server logs
                if(requestorData.getAccountLevel() >= Constants.DB_USER_ACCOUNT_LEVEL_OWNER)
                    logs = databaseManager.getLogsByServerId(request.getLimitingResourceId());
                else
                {
                    //retrieves the permissions of the requestor on the required server
                    PermissionsBean permissions =
                            databaseManager.getPermissions(request.getRequestorId(), request.getLimitingResourceId());

                    //is server manager?
                    if(Functions.isUserServerManager(request.getRequestorId(), permissions))
                        logs = databaseManager.getLogsByServerId(request.getLimitingResourceId());
                    else
                        ;
                }
            } break;

            //limits logs by severity
            case SEVERITY:
            {
                //only WMI owners can retrieve logs by severity
                if(requestorData.getAccountLevel() >= Constants.DB_USER_ACCOUNT_LEVEL_OWNER)
                    logs = databaseManager.getLogsBySeverity(request.getSeverity());
                else
                    ;
            } break;

            default: ; break;
        }

        //checks if logs data was retrieved
        if(logs != null)
        {
            //builds the response object
            ArrayList<LogDataComponent> data = new ArrayList<LogDataComponent>(logs.size());
            for(LogBean logBean : logs)
                data.add(new LogDataComponent(logBean));

            result = new DataRetrievalResponse<LogDataComponent>(data);
        }
        else
        {
            result = new DataRetrievalResponse<LogDataComponent>(
                    new ApplicationException(ExceptionMessages.APP_E_LOGS_RETRIEVAL_FAILED,
                                             "(" + request.getLimit() + "/" + request.getLimitingResourceId() + ")"));
        }

        return result;
    }

    /**
     * Retrieves system data.
     *
     * @param request system data retrieval request
     * @return a response to the data retrieval request
     */
    private DataRetrievalResponse<SystemDataComponent> retrieveSystemData(SystemDataRetrievalRequest request)
    {
        DataRetrievalResponse<SystemDataComponent> result = null;
        
        //attempts to retrieve the requestor data from the sessions manager
        UserBean requestorData = sessionsManager.getUserData(request.getRequestorId());

        //checks if the requestor is a WMI owner
        if(requestorData.getAccountLevel() >= Constants.DB_USER_ACCOUNT_LEVEL_OWNER)
        {
            //retrieves the virtualbox object reference for the required server
            IVirtualBox vbox = connectionsManager.getVirtualBoxReference(request.getResourceId(), request.getRequestorId());

            //checks if the vbox reference was retrieved
            if(vbox != null)
            {
                //builds the response data
                SystemVirtualBoxData vboxData = new SystemVirtualBoxData(vbox);
                SystemHostData hostData = new SystemHostData(vbox.getHost());

                result = new DataRetrievalResponse<SystemDataComponent>(new SystemDataComponent(request.getResourceId(), vboxData, hostData));
            }
            else
                result = new DataRetrievalResponse<SystemDataComponent>(new ApplicationException(ExceptionMessages.APP_E_VBOX_REF_NOT_AVAILABLE));
        }
        else
            result = new DataRetrievalResponse<SystemDataComponent>(new ApplicationException(ExceptionMessages.APP_E_OPERATION_NOT_ALLOWED));

        return result;
    }

    /**
     * Retrieves machine(s) data.
     *
     * @param request machine(s) data retrieval request
     * @return a response to the data retrieval request
     */
    private DataRetrievalResponse<MachineDataComponent> retrieveMachinesData(MachinesDataRetrievalRequest request)
    {
        DataRetrievalResponse<MachineDataComponent> result = null;

        //attemts to retrieve the virtualbox object for the required server
        IVirtualBox vbox = connectionsManager.getVirtualBoxReference(request.getServerId(), request.getRequestorId());

        //checks if the virtualbox object was retrieved
        if(vbox == null)
            return new DataRetrievalResponse<MachineDataComponent>(new ApplicationException(ExceptionMessages.APP_E_VBOX_REF_NOT_AVAILABLE));
        else
            ;

        //checks if full data for a single virtual machine is to be retrieved
        if(request.getResourceRequestType() == ResourceRequestType.SINGLE_RESOURCE)
        {
            try
            {
                //retrieves the virtual machine
                IMachine vboxData = vbox.getMachine(request.getResourceId());

                //retrieves machine data from the database
                VirtualResourceBean databaseData =
                        databaseManager.getVirtualResource(request.getResourceId(),
                                                           request.getServerId(),
                                                           VirtualResourceType.MACHINE);

                //<editor-fold defaultstate="collapsed" desc="Audio Settings">
                //retrieves the audio setup data
                AudioSettings audioSetup = new AudioSettings(vboxData.getAudioAdapter().getEnabled(),
                                                             vboxData.getAudioAdapter().getAudioController(),
                                                             vboxData.getAudioAdapter().getAudioDriver());
                //</editor-fold>

                //<editor-fold defaultstate="collapsed" desc="BIOS Settings">
                //retrieves the BIOS setup data
                IBIOSSettings bios = vboxData.getBIOSSettings();
                BIOSSettings biosSetup = new BIOSSettings(vboxData.getFirmwareType(),
                                                          vboxData.getHpetEnabled(),
                                                          vboxData.getRTCUseUTC(),
                                                          bios.getBootMenuMode(),
                                                          bios.getACPIEnabled(),
                                                          bios.getIOAPICEnabled(),
                                                          bios.getTimeOffset());
                //</editor-fold>

                //<editor-fold defaultstate="collapsed" desc="Boot Settings">
                //retrieves the boot setup data
                int maxBootDevices = vbox.getSystemProperties().getMaxBootPosition().intValue();
                DeviceType[] bootDevices = new DeviceType[maxBootDevices];
                for(int i = 1; i <= maxBootDevices; i++)
                    bootDevices[i-1] = vboxData.getBootOrder(new Long(i));
                BootSettings bootSetup = new BootSettings(bootDevices);
                //</editor-fold>

                //<editor-fold defaultstate="collapsed" desc="CPU Settings">
                //retrieves the CPU setup data
                CPUSettings cpuSetup = new CPUSettings(vboxData.getCPUHotPlugEnabled(),
                                                       vboxData.getCPUCount().intValue());
                //</editor-fold>

                //<editor-fold defaultstate="collapsed" desc="I/O Settings">
                //retrieves the I/O setup data
                IOSettings ioSetup = new IOSettings(vboxData.getIoCacheEnabled(),
                                                    vboxData.getIoCacheSize().intValue(),
                                                    vboxData.getIoBandwidthMax().intValue());
                //</editor-fold>

                //<editor-fold defaultstate="collapsed" desc="Memory Settings">
                //retrieves the memory setup data
                MemorySettings memorySetup = new MemorySettings(vboxData.getMemorySize().intValue(), 
                                                                vboxData.getMemoryBalloonSize().intValue(),
                                                                vboxData.getPageFusionEnabled());
                //</editor-fold>

                //<editor-fold defaultstate="collapsed" desc="Networks Settings">
                //retrieves the network adapters setup data
                int maxNetworkAdapters = vbox.getSystemProperties().getNetworkAdapterCount().intValue();
                NetworkAdapterSettings[] networksSetup = new NetworkAdapterSettings[maxNetworkAdapters];

                //retrieves the data for each network adapter
                for(int i = 0; i < maxNetworkAdapters; i++)
                {
                    //retrieves the network adapter
                    INetworkAdapter currentAdapter = vboxData.getNetworkAdapter(new Long(i));
                    String networkName = null, externalName = null;

                    //retrieves the network name for the adapter, based on the attachment type
                    switch(currentAdapter.getAttachmentType())
                    {
                        case HOST_ONLY:
                        case BRIDGED: 
                            networkName = currentAdapter.getHostInterface(); break;

                        case INTERNAL:
                        {
                            networkName = currentAdapter.getInternalNetwork();
                            InternalNetworkBean internalNetwork =
                                    databaseManager.getInternalNetwork(networkName, request.getServerId());
                            
                            if(internalNetwork != null)
                                externalName = internalNetwork.getNetworkName();
                            else
                                ;
                        } break;

                        case NAT:
                            networkName = currentAdapter.getNATNetwork(); break;

                        case VDE:
                            networkName = currentAdapter.getVDENetwork(); break;

                        default: ; break;
                    }

                    //retrieves the adapter configuration
                    NetworkAdapterSettings currentAdapterSetup =
                            new NetworkAdapterSettings(currentAdapter.getAdapterType(),
                                                       currentAdapter.getAttachmentType(),
                                                       currentAdapter.getEnabled(),
                                                       currentAdapter.getMACAddress(),
                                                       networkName,
                                                       externalName,
                                                       currentAdapter.getCableConnected(),
                                                       currentAdapter.getLineSpeed().intValue());

                    currentAdapterSetup.setBootPriority(currentAdapter.getBootPriority().intValue());

                    //<editor-fold defaultstate="collapsed" desc="NAT Engine Settings">
                    //retrieves the NAT engine setup data
                    if(currentAdapter.getAttachmentType() == NetworkAttachmentType.NAT)
                    {
                        //nat engine setup
                        NATEngineSettings natSetup = new NATEngineSettings();
                        INATEngine natEngine = currentAdapter.getNatDriver();

                        //main engine configuration (...)
                        Holder<Long> holderMTU = new Holder<Long>();
                        Holder<Long> holderSockSnd = new Holder<Long>();
                        Holder<Long> holderSockRcv = new Holder<Long>();
                        Holder<Long> holderWndSnd = new Holder<Long>();
                        Holder<Long> holderWNdRcv = new Holder<Long>();
                        natEngine.getNetworkSettings(holderMTU, holderSockSnd, holderSockRcv, holderWndSnd, holderWNdRcv);
                        natSetup.setEngineConfiguration(holderMTU.value, holderSockSnd.value, holderSockRcv.value,
                                                        holderWndSnd.value, holderWNdRcv.value, natEngine.getNetwork(),
                                                        natEngine.getHostIP());

                        //TFTP configuration
                        natSetup.setTFTPConfiguration(natEngine.getTftpPrefix(),
                                                      natEngine.getTftpBootFile(),
                                                      natEngine.getTftpNextServer());

                        //DNS configuration
                        natSetup.setDNSConfiguration(natEngine.getDnsPassDomain(),
                                                     natEngine.getDnsProxy(),
                                                     natEngine.getDnsUseHostResolver());

                        //alias mode
                        natSetup.setAliasMode(natEngine.getAliasMode());

                        //retrieves all port forwarding rules
                        for(String currentRawRule : natEngine.getRedirects())
                        {
                            StringTokenizer tokenizer = new StringTokenizer(currentRawRule, ",");

                            NATEngineForwardingRule currentRule =
                                    new NATEngineForwardingRule(tokenizer.nextToken(),
                                                                (tokenizer.nextToken().equals("1")) ? NATProtocol.TCP : NATProtocol.UDP,
                                                                tokenizer.nextToken(),
                                                                Integer.parseInt(tokenizer.nextToken()),
                                                                tokenizer.nextToken(),
                                                                Integer.parseInt(tokenizer.nextToken()));

                            natSetup.addNewForwardingRule(currentRule);
                        }

                        currentAdapterSetup.setNatEngineSetup(natSetup);
                    }
                    else
                        ;
                    //</editor-fold>

                    networksSetup[i] = currentAdapterSetup;
                }
                //</editor-fold>

                //<editor-fold defaultstate="collapsed" desc="Shared Folders Settings">
                //retrieves the shared folders setup data
                ISharedFolder[] sharedFolders = 
                        vboxData.getSharedFolders().toArray(new ISharedFolder[vboxData.getSharedFolders().size()]);
                SharedFolderSettings[] sharedFoldersSetup = new SharedFolderSettings[sharedFolders.length];
                String sharedFoldersRoot = databaseManager.getServerSharedFoldersRoot(request.getServerId());

                //retrieves each shared folder's data
                for(int i = 0; i < sharedFolders.length; i++)
                {
                    ISharedFolder currentFolder = sharedFolders[i];
                    String folderPath = currentFolder.getHostPath().substring(sharedFoldersRoot.length());
                    SharedFolderSettings folderSetup = new SharedFolderSettings(currentFolder.getName(),
                                                                                "{root}" + folderPath,
                                                                                currentFolder.isWritable(),
                                                                                currentFolder.isAccessible(),
                                                                                currentFolder.getLastAccessError());

                    sharedFoldersSetup[i] = folderSetup;
                }
                //</editor-fold>

                //<editor-fold defaultstate="collapsed" desc="Storage Settings">
                //retrieves the storage setup data
                int numberOfControllers = vboxData.getStorageControllers().size();
                int numberOfAttachments = vboxData.getMediumAttachments().size();

                //retrieves the storage controllers
                IStorageController[] controllers = 
                        vboxData.getStorageControllers().toArray(new IStorageController[numberOfControllers]);

                //retrieves the medium attachments
                IMediumAttachment[] attachments = 
                        vboxData.getMediumAttachments().toArray(new IMediumAttachment[numberOfAttachments]);

                //builds the storage data object
                MachineStorageData storageSetup = new MachineStorageData(controllers, attachments);
                //</editor-fold>

                //<editor-fold defaultstate="collapsed" desc="VRDP Settings">
                //retrieves the VRDP server setup data
                IVRDPServer vrdpServer = vboxData.getVRDPServer();
                VRDPSettings vrdpSetup = new VRDPSettings(vrdpServer.getEnabled(), 
                                                          vrdpServer.getPorts(),
                                                          vrdpServer.getNetAddress(),
                                                          vrdpServer.getAuthType(),
                                                          vrdpServer.getAuthTimeout().intValue(),
                                                          vrdpServer.getAllowMultiConnection(),
                                                          vrdpServer.getReuseSingleConnection(),
                                                          vrdpServer.getVideoChannel(),
                                                          vrdpServer.getVideoChannelQuality().intValue());
                //</editor-fold>

                //<editor-fold defaultstate="collapsed" desc="Video Settings">
                //retrieves the video setup data
                VideoSettings videoSetup = new VideoSettings(vboxData.getVRAMSize().intValue(),
                                                             vboxData.getAccelerate3DEnabled(),
                                                             vboxData.getAccelerate2DVideoEnabled());
                //</editor-fold>

                //builds the machine data object
                MachineDataComponent data = 
                        new MachineDataComponent(vboxData.getName(), vboxData.getOSTypeId(),
                                                 vboxData.getDescription(), vboxData.getState(),
                                                 vboxData.getSnapshotCount().intValue(),
                                                 databaseData, audioSetup, biosSetup, bootSetup,
                                                 cpuSetup, ioSetup, memorySetup, networksSetup,
                                                 sharedFoldersSetup, storageSetup,
                                                 vrdpSetup, videoSetup);

                result = new DataRetrievalResponse<MachineDataComponent>(data);
            }
            catch(WebServiceException e)
            {
                result = new DataRetrievalResponse<MachineDataComponent>(Functions.parseVirtualBoxException(e));
            }
        }
        else //partial data for multiple machines is to be retrieved
        {
            ArrayList<VirtualResourceBean> machinesData = null;

            //retrieves the requestor's user data and permissions
            UserBean userData = sessionsManager.getUserData(request.getRequestorId());
            PermissionsBean userPermissions = databaseManager.getPermissions(request.getRequestorId(), request.getServerId());

            //retrieves the machines based on the limit set in the request
            switch(request.getLimit())
            {
                //all machines are to be retrieved
                case NO_LIMIT:
                {
                    machinesData =
                            databaseManager.getVirtualResourcesByServer(request.getServerId(),
                                                                        VirtualResourceType.MACHINE);
                } break;

                //limits machines retrieval based on owner id
                case OWNER_ID:
                {
                    //only WMI owners and server managers can view other user's machines
                    if(userData.getAccountLevel() >= Constants.DB_USER_ACCOUNT_LEVEL_OWNER
                       || request.getRequestorId() == request.getOwnerId()
                       || Functions.isUserServerManager(request.getRequestorId(), userPermissions))
                    {
                        machinesData =
                                databaseManager.getVirtualResourcesByOwner(request.getOwnerId(),
                                                                           VirtualResourceType.MACHINE);
                    }
                    else
                        ;
                } break;

                default: ; break;
            }

            //checks if any machines data was retrieved
            if(machinesData != null)
            {
                ArrayList<MachineDataComponent> data = new ArrayList<MachineDataComponent>();

                //checks if the requestor is WMI owner or if he/she is server manager (for requests limited by server id)
                if(userData.getAccountLevel() >= Constants.DB_USER_ACCOUNT_LEVEL_OWNER
                   || Functions.isUserServerManager(request.getRequestorId(), userPermissions))
                {
                    IMachine currentMachine = null;
                    
                    for(VirtualResourceBean currentResource : machinesData)
                    {
                        try
                        {
                            //retrieves the required machine
                            currentMachine = vbox.getMachine(currentResource.getResourceId());

                            //adds the machine data to the response object
                            data.add(new MachineDataComponent(currentMachine.getName(),
                                                              currentMachine.getOSTypeId(),
                                                              currentMachine.getDescription(),
                                                              currentMachine.getState(),
                                                              currentResource));
                        }
                        catch(WebServiceException e){}//the machine was not found...
                    }
                }
                else
                {
                    boolean isRequestAuthorized = false;
                    AuthorizationRequest authRequest = null;
                    IMachine currentMachine = null;

                    //goes through each machine retrieved from the database
                    for(VirtualResourceBean currentResource : machinesData)
                    {
                        //checks if the user has authorization to view the machine
                        authRequest = new AuthorizationRequest(request.getRequestorId(),
                                                               request.getServerId(),
                                                               request.getRequestedAction(),
                                                               VirtualResourceType.MACHINE,
                                                               currentResource.getResourceId());

                        //possibly thrashing the permissions cache?
                        isRequestAuthorized = permissionsManager.isActionAuthorized(authRequest);

                        if(isRequestAuthorized)
                        {
                            try
                            {
                                //retrieves the virtual machine
                                currentMachine = vbox.getMachine(currentResource.getResourceId());

                                //adds the machine data to the response object
                                data.add(new MachineDataComponent(currentMachine.getName(),
                                                                  currentMachine.getOSTypeId(),
                                                                  currentMachine.getDescription(),
                                                                  currentMachine.getState(),
                                                                  currentResource));
                            }
                            catch(WebServiceException e){}//the machine was not found...
                        }
                        else
                            ;
                    }
                }

                result = new DataRetrievalResponse<MachineDataComponent>(data);
            }
            else
            {
                result = new DataRetrievalResponse<MachineDataComponent>(
                        new ApplicationException(ExceptionMessages.APP_E_MACHINES_RETRIEVAL_FAILED));
            }
        }

        return result;
    }

    /**
     * Retrieves snapshots data.
     *
     * @param request snapshots data retrieval request
     * @return a response to the data retrieval request
     */
    private DataRetrievalResponse<MachineSnapshotDataComponent> retrieveSnapshotsData(SnapshotsDataRetrievalRequest request)
    {
        DataRetrievalResponse<MachineSnapshotDataComponent> result = null;

        //attemts to retrieve the virtualbox object for the required server
        IVirtualBox vbox = connectionsManager.getVirtualBoxReference(request.getServerId(), request.getRequestorId());

        //checks if the virtualbox object was retrieved
        if(vbox == null)
            return new DataRetrievalResponse<MachineSnapshotDataComponent>(new ApplicationException(ExceptionMessages.APP_E_VBOX_REF_NOT_AVAILABLE));
        else
            ;

        try
        {
            //retrieves the virtual machine
            IMachine vboxData = vbox.getMachine(request.getResourceId());

            //builds the machine data object
            MachineSnapshotDataComponent data = null;
            try
            {
                data = new MachineSnapshotDataComponent(vboxData.getSnapshot(null));
                data.setCurrentSnapshot(vboxData.getCurrentSnapshot().getId());
            }
            catch(WebServiceException e){/* no snapshots */}

            result = new DataRetrievalResponse<MachineSnapshotDataComponent>(data);
        }
        catch(WebServiceException e)
        {
            result = new DataRetrievalResponse<MachineSnapshotDataComponent>(Functions.parseVirtualBoxException(e));
        }

        return result;
    }

    /**
     * Retrieves medium/media data.
     *
     * @param request medium/media data retrieval request
     * @return a response to the data retrieval request
     */
    private DataRetrievalResponse<MediumDataComponent> retrieveMediaData(MediaDataRetrievalRequest request)
    {
        DataRetrievalResponse<MediumDataComponent> result = null;

        //attemts to retrieve the virtualbox object for the required server
        IVirtualBox vbox = connectionsManager.getVirtualBoxReference(request.getServerId(), request.getRequestorId());

        //checks if the virtualbox object was retrieved
        if(vbox == null)
            return new DataRetrievalResponse<MediumDataComponent>(new ApplicationException(ExceptionMessages.APP_E_VBOX_REF_NOT_AVAILABLE));
        else
            ;

        //checks if full data for a single medium is to be retrieved
        if(request.getResourceRequestType() == ResourceRequestType.SINGLE_RESOURCE)
        {
            try
            {
                //retrieved the medium data based on the device type
                IMedium vboxData = null;
                switch(request.getMediumDeviceType())
                {
                    case HARD_DISK: vboxData = vbox.getHardDisk(request.getResourceId()); break;
                    case DVD: vboxData = vbox.getDVDImage(request.getResourceId()); break;
                    case FLOPPY: vboxData = vbox.getFloppyImage(request.getResourceId()); break;
                    default: ; break;
                }

                //checks if the medium data was retrieved
                if(vboxData != null)
                {
                    VirtualResourceBean databaseData =
                            databaseManager.getVirtualResource(request.getResourceId(),
                                                               request.getServerId(),
                                                               VirtualResourceType.MEDIUM);

                    if(databaseData != null && databaseData.isValid())
                    {
                        vboxData.refreshState(); //makes sure the latest state is available

                        //builds the response object
                        result = new DataRetrievalResponse<MediumDataComponent>(
                                new MediumDataComponent(databaseData, vboxData));
                    }
                    else
                    {
                        result = new DataRetrievalResponse<MediumDataComponent>(
                            new ApplicationException(ExceptionMessages.APP_E_MEDIUM_RETRIEVAL_FAILED));
                    }
                }
                else
                {
                    result = new DataRetrievalResponse<MediumDataComponent>(
                            new ApplicationException(ExceptionMessages.APP_E_MEDIUM_RETRIEVAL_FAILED));
                }
            }
            catch(WebServiceException e)
            {
                result = new DataRetrievalResponse<MediumDataComponent>(Functions.parseVirtualBoxException(e));
            }
        }
        else //partial data for multiple media is to be retrieved
        {
            ArrayList<VirtualResourceBean> mediaData = null;

            //retrieves the requestor's data
            UserBean userData = sessionsManager.getUserData(request.getRequestorId());
            //retrieves the requestor's permissions
            PermissionsBean userPermissions = databaseManager.getPermissions(request.getRequestorId(), request.getServerId());

            //retrieves the media based on the limit set in the request
            switch(request.getLimit())
            {
                //all available media
                case NO_LIMIT:
                {
                    mediaData =
                            databaseManager.getVirtualResourcesByServer(request.getServerId(),
                                                                        VirtualResourceType.MEDIUM);
                } break;

                //limits media retrieval based on owner id
                case OWNER_ID:
                {
                    //only WMI owners and server managers can view other user's media
                    if(userData.getAccountLevel() >= Constants.DB_USER_ACCOUNT_LEVEL_OWNER
                       || request.getRequestorId() == request.getOwnerId()
                       || Functions.isUserServerManager(request.getRequestorId(), userPermissions))
                    {
                        mediaData =
                                databaseManager.getVirtualResourcesByOwner(request.getOwnerId(),
                                                                           VirtualResourceType.MEDIUM);
                    }
                    else
                        ;
                } break;

                default: ; break;
            }

            //checks if any media were retrieved
            if(mediaData != null)
            {
                ArrayList<MediumDataComponent> data = new ArrayList<MediumDataComponent>();

                //checks if the requestor is WMI owner or if he/she is server manager (for requests limited by server id)
                if(userData.getAccountLevel() >= Constants.DB_USER_ACCOUNT_LEVEL_OWNER
                   || Functions.isUserServerManager(request.getRequestorId(), userPermissions))
                {
                    IMedium currentMedium = null;

                    for(VirtualResourceBean currentResource : mediaData)
                    {
                        try
                        {
                            //retrieves the medium, based on the supplied device type
                            switch(request.getMediumDeviceType())
                            {
                                case HARD_DISK: 
                                    currentMedium = vbox.getHardDisk(currentResource.getResourceId()); break;

                                case DVD:
                                    currentMedium = vbox.getDVDImage(currentResource.getResourceId()); break;

                                case FLOPPY:
                                    currentMedium = vbox.getFloppyImage(currentResource.getResourceId()); break;

                                default: ; break;
                            }

                            //checks if the medium was retrieved
                            if(currentMedium != null)
                            {
                                //adds the medium data to the response
                                data.add(new MediumDataComponent(currentResource,
                                                                 currentMedium.getName(),
                                                                 currentMedium.getDescription(),
                                                                 currentMedium.getState()));
                            }
                            else
                                ;
                        }
                        catch(WebServiceException e){} //medium not found

                        currentMedium = null;
                    }
                }
                else
                {
                    boolean isRequestAuthorized = false;
                    AuthorizationRequest authRequest = null;
                    IMedium currentMedium = null;

                    for(VirtualResourceBean currentResource : mediaData)
                    {
                        //checks if the user has authorization to view the medium
                        authRequest = new AuthorizationRequest(request.getRequestorId(),
                                                               request.getServerId(),
                                                               request.getRequestedAction(),
                                                               VirtualResourceType.MEDIUM,
                                                               currentResource.getResourceId());

                        //possibly thrashing the permissions cache?
                        isRequestAuthorized = permissionsManager.isActionAuthorized(authRequest);

                        if(isRequestAuthorized)
                        {
                            try
                            {
                                //retrieves the medium, based on the supplied device type
                                switch(request.getMediumDeviceType())
                                {
                                    case HARD_DISK:
                                        currentMedium = vbox.getHardDisk(currentResource.getResourceId()); break;

                                    case DVD:
                                        currentMedium = vbox.getDVDImage(currentResource.getResourceId()); break;

                                    case FLOPPY:
                                        currentMedium = vbox.getFloppyImage(currentResource.getResourceId()); break;

                                    default: ; break;
                                }

                                //checks if the medium was retrieved
                                if(currentMedium != null)
                                {
                                    //adds the medium data to the response
                                    data.add(new MediumDataComponent(currentResource,
                                                                     currentMedium.getName(),
                                                                     currentMedium.getDescription(),
                                                                     currentMedium.getState()));
                                }
                                else
                                    ;
                            }
                            catch(WebServiceException e){}//the medium was not found...
                        }
                        else
                            ;

                        currentMedium = null;
                    }
                }

                result = new DataRetrievalResponse<MediumDataComponent>(data);
            }
            else
            {
                result = new DataRetrievalResponse<MediumDataComponent>(
                        new ApplicationException(ExceptionMessages.APP_E_MEDIA_RETRIEVAL_FAILED));
            }
        }

        return result;
    }

    /**
     * Retrieves network(s) data.
     *
     * @param request network(s) data retrieval request
     * @return a response to the data retrieval request
     */
    private DataRetrievalResponse<NetworkDataComponent> retrieveNetworksData(NetworksDataRetrievalRequest request)
    {
        DataRetrievalResponse<NetworkDataComponent> result = null;

        //attemts to retrieve the virtualbox object for the required server
        IVirtualBox vbox = connectionsManager.getVirtualBoxReference(request.getServerId(), request.getRequestorId());

        //checks if the virtualbox object was retrieved
        if(vbox == null)
            return new DataRetrievalResponse<NetworkDataComponent>(new ApplicationException(ExceptionMessages.APP_E_VBOX_REF_NOT_AVAILABLE));
        else
            ;

        //checks if full data for a single network is to be retrieved
        if(request.getResourceRequestType() == ResourceRequestType.SINGLE_RESOURCE)
        {
            try
            {
                //retrieves network data from the database
                VirtualResourceBean databaseData =
                        databaseManager.getVirtualResource(request.getResourceId(),
                                                           request.getServerId(),
                                                           VirtualResourceType.NETWORK);

                //determines the type of the network
                switch(request.getNetworkType())
                {
                    case HOST_ONLY: //host-only and bridged
                    {
                        //attempts to retrieve the network data
                        IHostNetworkInterface networkInterface = vbox.getHost().findHostNetworkInterfaceById(request.getResourceId());
                        DHCPServerConfiguration dhcpConfig = null;

                        //checks if a dhcp server is available
                        try
                        {
                            //retrieves dhcp server data
                            IDHCPServer dhcpServer = vbox.findDHCPServerByNetworkName(networkInterface.getNetworkName());
                            dhcpConfig = new DHCPServerConfiguration(dhcpServer.getIPAddress(),
                                                                     dhcpServer.getNetworkMask(),
                                                                     dhcpServer.getLowerIP(),
                                                                     dhcpServer.getUpperIP(),
                                                                     dhcpServer.getEnabled());
                        }
                        catch(WebServiceException e){}

                        //builds the response object
                        HostNetworkConfiguration networkConfig = new HostNetworkConfiguration(networkInterface, dhcpConfig, databaseData);
                        result = new DataRetrievalResponse<NetworkDataComponent>(new NetworkDataComponent(networkConfig));
                    } break;

                    case INTERNAL:
                    {
                        //retrieves the network data
                        InternalNetworkBean network = databaseManager.getInternalNetwork(request.getResourceId(), request.getServerId());
                        DHCPServerConfiguration dhcpConfig = null;

                        //checks if a dhcp server is available
                        if(network.isDHCPAvailable())
                        {
                            try
                            {
                                //retrieves dhcp server data
                                IDHCPServer dhcpServer = vbox.findDHCPServerByNetworkName(network.getNetworkId());
                                dhcpConfig = new DHCPServerConfiguration(dhcpServer.getIPAddress(),
                                                                         dhcpServer.getNetworkMask(),
                                                                         dhcpServer.getLowerIP(),
                                                                         dhcpServer.getUpperIP(),
                                                                         dhcpServer.getEnabled());
                            }
                            catch(WebServiceException e){}
                        }
                        else
                            ;

                        //builds the response object
                        InternalNetworkConfiguration networkConfig = new InternalNetworkConfiguration(network, dhcpConfig, databaseData);
                        result = new DataRetrievalResponse<NetworkDataComponent>(new NetworkDataComponent(networkConfig));
                    } break;

                    default:
                    {
                        result = new DataRetrievalResponse<NetworkDataComponent>(
                                new ApplicationException(ExceptionMessages.APP_E_NETWORK_TYPE_INVALID));
                    } break;
                }
            }
            catch(WebServiceException e)
            {
                result = new DataRetrievalResponse<NetworkDataComponent>(Functions.parseVirtualBoxException(e));
            }
        }
        else //partial data for multiple networks is to be retrieved
        {
            ArrayList<VirtualResourceBean> networksData = null;

            //retrieves the requestor's data
            UserBean userData = sessionsManager.getUserData(request.getRequestorId());
            //retrieves ther equestor's permissions
            PermissionsBean userPermissions = databaseManager.getPermissions(request.getRequestorId(), request.getServerId());

            //retrieves the networks based on the limit set in the request
            switch(request.getLimit())
            {
                //data for all available networks is to be retrieved
                case NO_LIMIT:
                {
                    networksData =
                            databaseManager.getVirtualResourcesByServer(request.getServerId(),
                                                                        VirtualResourceType.NETWORK);
                } break;

                //limits networks retrieval based on owner id
                case OWNER_ID:
                {
                    //only WMI owners and server managers can view other user's networks
                    if(userData.getAccountLevel() >= Constants.DB_USER_ACCOUNT_LEVEL_OWNER
                       || request.getRequestorId() == request.getOwnerId()
                       || Functions.isUserServerManager(request.getRequestorId(), userPermissions))
                    {
                        networksData =
                                databaseManager.getVirtualResourcesByOwner(request.getOwnerId(),
                                                                           VirtualResourceType.NETWORK);
                    }
                    else
                        ;
                } break;

                default: ; break;
            }

            //checks if any networks data was retrieved
            if(networksData != null)
            {
                ArrayList<NetworkDataComponent> data = new ArrayList<NetworkDataComponent>();

                //checks if the requestor is WMI owner or if he/she is server manager (for requests limited by server id)
                if(userData.getAccountLevel() >= Constants.DB_USER_ACCOUNT_LEVEL_OWNER
                   || Functions.isUserServerManager(request.getRequestorId(), userPermissions))
                {
                    for(VirtualResourceBean currentResource : networksData)
                    {
                        try
                        {
                            //retrieves network data based on its type
                            switch(request.getNetworkType())
                            {
                                //host-only and bridged networks data
                                case HOST_ONLY:
                                {
                                    //retrieves the network data
                                    IHostNetworkInterface network =
                                            vbox.getHost().findHostNetworkInterfaceById(currentResource.getResourceId());

                                    //adds the data to the response
                                    data.add(new NetworkDataComponent(network.getName(),
                                                                      request.getNetworkType(),
                                                                      currentResource,
                                                                      network.getInterfaceType()));
                                } break;

                                //internal networks data
                                case INTERNAL:
                                {
                                    //retrieves the network data
                                    InternalNetworkBean network =
                                            databaseManager.getInternalNetwork(currentResource.getResourceId(),
                                                                               request.getServerId());

                                    //adds the data to the response
                                    if(network != null)
                                    {
                                        data.add(new NetworkDataComponent(network.getNetworkName(),
                                                                          request.getNetworkType(),
                                                                          currentResource,
                                                                          null));
                                    }
                                    else
                                        ;
                                } break;

                                default: ; break;
                            }
                        }
                        catch(WebServiceException e){}//the network was not found...
                    }
                }
                else
                {
                    boolean isRequestAuthorized = false;
                    AuthorizationRequest authRequest = null;

                    for(VirtualResourceBean currentResource : networksData)
                    {
                        //checks if the user has authorization to view the network
                        authRequest = new AuthorizationRequest(request.getRequestorId(),
                                                               request.getServerId(),
                                                               request.getRequestedAction(),
                                                               VirtualResourceType.NETWORK,
                                                               currentResource.getResourceId());

                        //possibly thrashing the permissions cache?
                        isRequestAuthorized = permissionsManager.isActionAuthorized(authRequest);

                        if(isRequestAuthorized)
                        {
                            //retrieves network data based on its type
                            switch(request.getNetworkType())
                            {
                                //host-only and bridged networks data
                                case HOST_ONLY:
                                {
                                    try
                                    {
                                        //retrieves the network data
                                        IHostNetworkInterface network =
                                                vbox.getHost().findHostNetworkInterfaceById(currentResource.getResourceId());

                                        //adds the data to the response
                                        data.add(new NetworkDataComponent(network.getName(),
                                                                          request.getNetworkType(),
                                                                          currentResource,
                                                                          network.getInterfaceType()));
                                    }
                                    catch(WebServiceException e){}//the network was not found...
                                } break;

                                //internal network data
                                case INTERNAL:
                                {
                                    //retrieves the network data
                                    InternalNetworkBean network =
                                            databaseManager.getInternalNetwork(currentResource.getResourceId(),
                                                                               request.getServerId());

                                    //adds the data to the response
                                    if(network != null)
                                    {
                                        data.add(new NetworkDataComponent(network.getNetworkName(),
                                                                          request.getNetworkType(), 
                                                                          currentResource,
                                                                          null));
                                    }
                                    else
                                        ;
                                } break;

                                default: ; break;
                            }
                        }
                        else
                            ;
                    }
                }

                result = new DataRetrievalResponse<NetworkDataComponent>(data);
            }
            else
            {
                result = new DataRetrievalResponse<NetworkDataComponent>(
                        new ApplicationException(ExceptionMessages.APP_E_NETWORKS_RETRIEVAL_FAILED));
            }
        }

        return result;
    }

    /**
     * Retrieves various data.
     *
     * @param request data retrieval request
     * @return a response to the retrieval request
     */
    private DataRetrievalResponse<MiscDataComponent> retrieveMiscellaneousData(MiscDataRetrievalRequest request)
    {
        DataRetrievalResponse<MiscDataComponent> result = null;

        //determines the type of virtual resource based on the request type
        VirtualResourceType resourceType = null;
        switch(request.getRequestType())
        {
            case GUEST_OS_TYPES: resourceType = VirtualResourceType.MACHINE; break;
            case MEDIUM_FORMATS: resourceType = VirtualResourceType.MEDIUM; break;
            default: resourceType = VirtualResourceType.INVALID; break;
        }

        //builds an authorization request and retireves the results
        boolean isActionAuthorized = permissionsManager.isActionAuthorized(
                                        new SimpleAuthorizationRequest(request.getRequestorId(),
                                                                       request.getResourceId(),
                                                                       request.getRequestedAction(),
                                                                       resourceType));

        //checks if the requested action is allowed
        if(isActionAuthorized)
        {
            //attemts to retrieve the virtualbox object for the required server
            IVirtualBox vbox = connectionsManager.getVirtualBoxReference(request.getResourceId(), request.getRequestorId());

            //checks if the virtualbox object was retrieved
            if(vbox == null)
                return new DataRetrievalResponse<MiscDataComponent>(new ApplicationException(ExceptionMessages.APP_E_VBOX_REF_NOT_AVAILABLE));
            else
                ;

            try
            {
                MiscDataComponent data = null; //result

                //retrieves the proper information and builds the result based on the requested resource
                switch(request.getRequestType())
                {
                    //a list of guest OS types is requested
                    case GUEST_OS_TYPES:
                    {
                        List<IGuestOSType> osTypes = vbox.getGuestOSTypes();
                        data = new MiscDataComponent(osTypes.toArray(new IGuestOSType[osTypes.size()]));
                    } break;

                    //a list of supported medium formats is requested
                    case MEDIUM_FORMATS:
                    {
                        List<IMediumFormat> mediumFormats = vbox.getSystemProperties().getMediumFormats();
                        data = new MiscDataComponent(mediumFormats.toArray(new IMediumFormat[mediumFormats.size()]));
                    } break;

                    default: ; break;
                }

                //checks if any data was retrieved and builds the appropriate response
                if(data != null)
                    result = new DataRetrievalResponse<MiscDataComponent>(data);
                else
                {
                    result = new DataRetrievalResponse<MiscDataComponent>(
                            new ApplicationException(ExceptionMessages.APP_E_MISC_DATA_RETRIEVAL_FAILED));
                }
            }
            catch(WebServiceException e)
            {
                result = new DataRetrievalResponse<MiscDataComponent>(Functions.parseVirtualBoxException(e));
            }
        }
        else
            result = new DataRetrievalResponse<MiscDataComponent>(new ApplicationException(ExceptionMessages.APP_E_OPERATION_NOT_ALLOWED));

        return result;
    }
}
